home *** CD-ROM | disk | FTP | other *** search
/ Ian & Stuart's Australian Mac: Not for Sale / Another.not.for.sale (Australia).iso / hold me in your arms / PGP 2.6 / pgp2.6 Source / src / armor.c < prev    next >
C/C++ Source or Header  |  1994-05-07  |  28KB  |  1,077 lines

  1. /*    armor.c  - ASCII/binary encoding/decoding based partly on PEM RFC1113.
  2.     PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
  3.  
  4.         (c) Copyright 1990-1994 by Philip Zimmermann.  All rights reserved.
  5.         The author assumes no liability for damages resulting from the use
  6.         of this software, even if the damage results from defects in this
  7.         software.  No warranty is expressed or implied.
  8.  
  9.         Note that while most PGP source modules bear Philip Zimmermann's
  10.         copyright notice, many of them have been revised or entirely written
  11.         by contributors who frequently failed to put their names in their
  12.         code.  Code that has been incorporated into PGP from other authors
  13.         was either originally published in the public domain or is used with
  14.         permission from the various authors.
  15.  
  16.         PGP is available for free to the public under certain restrictions.
  17.         See the PGP User's Guide (included in the release package) for
  18.         important information about licensing, patent restrictions on
  19.         certain algorithms, trademarks, copyrights, and export controls.
  20. */
  21.  
  22.  
  23. #include <ctype.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include "mpilib.h"
  27. #include "fileio.h"
  28. #include "mpiio.h"
  29. #include "language.h"
  30. #include "pgp.h"
  31. #include "crypto.h"
  32. #include "armor.h"
  33.  
  34. static int dpem_file(char *infile, char *outfile);
  35. static crcword crchware(byte ch, crcword poly, crcword accum);
  36. static int pem_file(char *infilename, char *outfilename, char *clearfilename);
  37. static int pemdecode(FILE *in, FILE *out);
  38. static void mk_crctbl(crcword poly);
  39. static boolean is_pemfile(char *infile);
  40.  
  41. /*     Begin PEM routines.
  42.     This converts a binary file into printable ASCII characters, in a
  43.     radix-64 form mostly compatible with the PEM RFC1113 format.
  44.     This makes it easier to send encrypted files over a 7-bit channel.
  45. */
  46.  
  47. /* Index this array by a 6 bit value to get the character corresponding
  48.  * to that value.
  49.  */
  50. static
  51. unsigned char bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\
  52. abcdefghijklmnopqrstuvwxyz0123456789+/";
  53.  
  54. /* Index this array by a 7 bit value to get the 6-bit binary field
  55.  * corresponding to that value.  Any illegal characters return high bit set.
  56.  */
  57. static
  58. unsigned char asctobin[] = {
  59.     0200,0200,0200,0200,0200,0200,0200,0200,
  60.     0200,0200,0200,0200,0200,0200,0200,0200,
  61.     0200,0200,0200,0200,0200,0200,0200,0200,
  62.     0200,0200,0200,0200,0200,0200,0200,0200,
  63.     0200,0200,0200,0200,0200,0200,0200,0200,
  64.     0200,0200,0200,0076,0200,0200,0200,0077,
  65.     0064,0065,0066,0067,0070,0071,0072,0073,
  66.     0074,0075,0200,0200,0200,0200,0200,0200,
  67.     0200,0000,0001,0002,0003,0004,0005,0006,
  68.     0007,0010,0011,0012,0013,0014,0015,0016,
  69.     0017,0020,0021,0022,0023,0024,0025,0026,
  70.     0027,0030,0031,0200,0200,0200,0200,0200,
  71.     0200,0032,0033,0034,0035,0036,0037,0040,
  72.     0041,0042,0043,0044,0045,0046,0047,0050,
  73.     0051,0052,0053,0054,0055,0056,0057,0060,
  74.     0061,0062,0063,0200,0200,0200,0200,0200
  75. };
  76. static long    infile_line;        /* Current line number for mult decodes */
  77.  
  78. /************************************************************************/
  79.  
  80. /* CRC Routines. */
  81. /*    These CRC functions are derived from code in chapter 19 of the book 
  82.     "C Programmer's Guide to Serial Communications", by Joe Campbell.
  83.     Generalized to any CRC width by Philip Zimmermann.
  84. */
  85.  
  86. #define byte unsigned char
  87.  
  88. #define CRCBITS 24    /* may be 16, 24, or 32 */
  89. /* #define maskcrc(crc) ((crcword)(crc)) */    /* if CRCBITS is 16 or 32 */
  90. #define maskcrc(crc) ((crc) & 0xffffffL)    /* if CRCBITS is 24 */
  91. #define CRCHIBIT ((crcword) (1L<<(CRCBITS-1))) /* 0x8000 if CRCBITS is 16 */
  92. #define CRCSHIFTS (CRCBITS-8)
  93.  
  94. /*
  95.  * Notes on making a good 24-bit CRC--
  96.  * The primitive irreducible polynomial of degree 23 over GF(2),
  97.  * 040435651 (octal), comes from Appendix C of "Error Correcting Codes,
  98.  * 2nd edition" by Peterson and Weldon, page 490.  This polynomial was
  99.  * chosen for its uniform density of ones and zeros, which has better
  100.  * error detection properties than polynomials with a minimal number of
  101.  * nonzero terms.  Multiplying this primitive degree-23 polynomial by
  102.  * the polynomial x+1 yields the additional property of detecting any
  103.  * odd number of bits in error, which means it adds parity.  This 
  104.  * approach was recommended by Neal Glover.
  105.  *
  106.  * To multiply the polynomial 040435651 by x+1, shift it left 1 bit and
  107.  * bitwise add (xor) the unshifted version back in.  Dropping the unused 
  108.  * upper bit (bit 24) produces a CRC-24 generator bitmask of 041446373 
  109.  * octal, or 0x864cfb hex.  
  110.  *
  111.  * You can detect spurious leading zeros or framing errors in the 
  112.  * message by initializing the CRC accumulator to some agreed-upon 
  113.  * nonzero "random-like" value, but this is a bit nonstandard.  
  114.  */
  115.  
  116. #define CCITTCRC 0x1021 /* CCITT's 16-bit CRC generator polynomial */
  117. #define PRZCRC 0x864cfbL /* PRZ's 24-bit CRC generator polynomial */
  118. #define CRCINIT 0xB704CEL    /* Init value for CRC accumulator */
  119.  
  120. static
  121. crcword crctable[256];        /* Table for speeding up CRC's */
  122.  
  123. /*
  124.  * mk_crctbl derives a CRC lookup table from the CRC polynomial.
  125.  * The table is used later by the crcbytes function given below.
  126.  * mk_crctbl only needs to be called once at the dawn of time.
  127.  *
  128.  * The theory behind mk_crctbl is that table[i] is initialized
  129.  * with the CRC of i, and this is related to the CRC of i>>1,
  130.  * so the CRC of i>>1 (pointed to by p) can be used to derive
  131.  * the CRC of i (pointed to by q).
  132.  */
  133. static
  134. void mk_crctbl(crcword poly)
  135. {
  136.     int i;
  137.     crcword t, *p, *q;
  138.     p = q = crctable;
  139.     *q++ = 0;
  140.     *q++ = poly;
  141.     for (i = 1; i < 128; i++) {
  142.         t = *++p;
  143.         if (t & CRCHIBIT) {
  144.             t <<= 1;
  145.             *q++ = t ^ poly;
  146.             *q++ = t;
  147.         } else {
  148.             t <<= 1;
  149.             *q++ = t;
  150.             *q++ = t ^ poly;
  151.         }
  152.     }
  153. }
  154.  
  155. /*
  156.  * Accumulate a buffer's worth of bytes into a CRC accumulator,
  157.  * returning the new CRC value.
  158.  */
  159. crcword
  160. crcbytes(byte *buf, unsigned len, register crcword accum)
  161. {
  162.     do {
  163.         accum = accum<<8 ^ crctable[(byte)(accum>>CRCSHIFTS) ^ *buf++];
  164.     } while (--len);
  165.     return maskcrc(accum);
  166. } /* crcbytes */
  167.  
  168. /* Initialize the CRC table using our codes */
  169. void init_crc(void)
  170. {
  171.     mk_crctbl(PRZCRC);
  172. }
  173.  
  174.  
  175. /************************************************************************/
  176.  
  177.  
  178. /* ENC is the basic 1 character encoding function to make a char printing */
  179. #define ENC(c) ((int)bintoasc[((c) & 077)])
  180. #define PAD        '='
  181.  
  182. /*
  183.  * output one group of up to 3 bytes, pointed at by p, on file f.
  184.  * if fewer than 3 are present, the 1 or two extras must be zeros.
  185.  */
  186. static void outdec(char *p, FILE *f, int count)
  187. {
  188.     int c1, c2, c3, c4;
  189.  
  190.     c1 = *p >> 2;
  191.     c2 = ((*p << 4) & 060) | ((p[1] >> 4) & 017);
  192.     c3 = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03);
  193.     c4 = p[2] & 077;
  194.     putc(ENC(c1), f);
  195.     putc(ENC(c2), f);
  196.     if (count == 1) {
  197.         putc(PAD, f);
  198.         putc(PAD, f);
  199.     } else {
  200.         putc(ENC(c3), f);
  201.         if (count == 2)
  202.             putc(PAD, f);
  203.         else
  204.             putc(ENC(c4), f);
  205.     }
  206. }    /* outdec */
  207.  
  208.  
  209. /* Output the CRC value, MSB first per normal CRC conventions */
  210. static void outcrc (word32 crc, FILE *outFile)
  211. {
  212.     char crcbuf[4];
  213.     crcbuf[0] = (crc>>16) & 0xff;
  214.     crcbuf[1] = (crc>>8) & 0xff;
  215.     crcbuf[2] = (crc>>0) & 0xff;
  216.     putc(PAD,outFile);
  217.     outdec (crcbuf,outFile,3);
  218.     putc('\n',outFile);
  219. }    /* outcrc */
  220.  
  221. /* Return filename for output (text mode), but replace last letter(s) of
  222.  * filename with the ascii for num.  It will use the appropriate number
  223.  * of digits for ofnum when converting num, so if ofnum < 10, use 1 digit,
  224.  * >= 10 and < 100 use 2 digits, >= 100 and < 1000 use 3 digits.  If its
  225.  * >= 1000, then we have other problems to worry about, and this might do
  226.  * weird things.
  227.  */
  228. static char *numFilename( char *fname, int num, int ofnum)
  229. {
  230.     static char    fnamenum[MAX_PATH];
  231.     int        len;
  232.     int        offset = 1;
  233.  
  234.     strcpy (fnamenum, fname);
  235.     len = strlen (fnamenum);
  236.     do {
  237.         fnamenum[len-offset] = '0' + (num%10);
  238.         num /= 10;
  239.         ofnum /= 10;
  240.         offset++;
  241.     } while (ofnum >= 1 && offset < 4);
  242.     return fnamenum;
  243. }
  244.  
  245. /*
  246.  * Reads and discards a line from the given file.  Returns -1 on error or
  247.  * EOF, 0 if the line is blank, and 1 if the line is not blank.
  248.  */
  249. static int
  250. skipline(FILE *f)
  251. {
  252.     int state, flag, c;
  253.  
  254.     state = 0;
  255.     flag = 0;
  256.     for (;;) {
  257.         c = getc(f);
  258.         if (c == '\n')
  259.             return flag;
  260.         if (state) {
  261.             ungetc(c, f);
  262.             return flag;
  263.         }
  264.         if (c == EOF)
  265.             return -1;
  266.         if (c == '\r')
  267.             state = 1;
  268.         else if (c != ' ')
  269.             flag = 1;
  270.     }
  271. } /* skipline */
  272.  
  273. /*
  274.  * Copies a line from the input file to the output.  Does NOT copy the
  275.  * trailing newline.  Returns -1 on EOF or error, 0 if the line was terminated
  276.  * by EOF, and 1 if the line was terminated with a newline sequence.
  277.  */
  278. static int
  279. copyline(FILE *in, FILE *out)
  280. {
  281.     int state, flag, c;
  282.  
  283.     state = 0;
  284.     for (;;) {
  285.         c = getc(in);
  286.         if (c == '\n')
  287.             return 1;
  288.         if (state) {
  289.             ungetc(c, in);
  290.             return 1;
  291.         }
  292.         if (c == EOF)
  293.             return 0;
  294.         if (c == '\r')
  295.             state = 1;
  296.         else
  297.             putc(c, out);
  298.     }
  299. } /* copyline */
  300.  
  301. /*
  302.  * Reads a line from file f, up to the size of the buffer.  The line in the
  303.  * buffer will NOT include line termination, although any of (CR, LF, CRLF)
  304.  * is accepted on input.  The return value is -1 on error, 0 if the line
  305.  * was terminated abnormally (EOF, error, or out of buffer space), and
  306.  * 1 if the line was terminated normally.
  307.  *
  308.  * Passing in a buffer less than 2 characters long is not a terribly bright
  309.  * idea.
  310.  */
  311. static int
  312. getline(char *buf, int n, FILE *f)
  313. {
  314.     int state;
  315.     char *p;
  316.     int c;
  317.  
  318.     state = 0;
  319.     p = buf;
  320.     for (;;) {
  321.         c = getc(f);
  322.         if (c == '\n') {
  323.              *p = 0;
  324.             return 1;    /* Line terminated with \n or \r\n */
  325.         }
  326.         if (state) {
  327.             ungetc(c, f);
  328.             *p = 0;
  329.             return 1;    /* Line terminated with \r */
  330.         }
  331.         if (c == EOF) {
  332.             *p = 0;
  333.             return (p == buf) ? -1 : 0;    /* Error */
  334.         }
  335.         if (c == '\r')
  336.             state = 1;
  337.         else if (--n > 0) {
  338.             *p++ = c;
  339.         } else {
  340.             ungetc(c, f);
  341.             *p = 0;
  342.             return 0;    /* Out of buffer space */
  343.         }
  344.     } /* for (;;) */
  345. } /* getline */
  346.  
  347. /*
  348.  * Read a line from file f, buf must be able to hold at least 80 characters.
  349.  * Strips trailing spaces and line terminator, can read LF, CRLF and CR
  350.  * textfiles.  Anything after 80 characters is ignored.  It can't be ASCII
  351.  * armor anyway.
  352.  */
  353. static char *
  354. get_armor_line(char *buf, FILE *f)
  355. {
  356.     int c, n = 79;
  357.     char *p = buf;
  358.  
  359.     do {
  360.         c = getc(f);
  361.         if (c == '\n' || c == '\r' || c == EOF)
  362.             break;
  363.         *p++ = c;
  364.     } while (--n > 0);
  365.     if (p == buf && c == EOF) {
  366.         *buf = '\0';
  367.         return NULL;
  368.     }
  369.     /* skip to end of line */
  370.     while (c != '\n' && c != '\r' && c != EOF)
  371.         c = getc(f);
  372.     if (c == '\r' && (c = getc(f)) != '\n')
  373.         ungetc(c, f);
  374.     while (--p >= buf && *p == ' ')
  375.         ;
  376.     *++p = '\0';
  377.     return buf;
  378. }
  379.  
  380.  
  381. /*
  382.  * Encode a file in sections.  64 ASCII bytes * 720 lines = 46K, 
  383.  * recommended max.  Usenet message size is 50K so this leaves a nice 
  384.  * margin for .signature.  In the interests of orthogonality and 
  385.  * programmer laziness no check is made for a message containing only 
  386.  * a few lines (or even just an 'end')    after a section break. 
  387.  */
  388. #define LINE_LEN    48L
  389. int pem_lines = 720;
  390. #define BYTES_PER_SECTION    (LINE_LEN * pem_lines)
  391.  
  392. #if 1
  393. /* This limit is advisory only; longer lines are handled properly.
  394.  * The only requirement is that this be at least as long as the longest
  395.  * delimiter string used by PGP
  396.  * (e.g. "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n")
  397.  */
  398. #define MAX_LINE_SIZE 80
  399. #else
  400. #ifdef MSDOS    /* limited stack space */
  401. #define MAX_LINE_SIZE    256
  402. #else
  403. #define MAX_LINE_SIZE    1024
  404. #endif
  405. #endif
  406.  
  407. #ifndef VMS
  408. /* armored files are opened in binary mode so that CRLF/LF/CR files
  409.    can be handled by all systems */
  410. #define    FOPRPEM    FOPRBIN
  411. #else
  412. #define    FOPRPEM    FOPRTXT
  413. #endif
  414.  
  415. extern boolean verbose;    /* Undocumented command mode in PGP.C */
  416. extern boolean filter_mode;
  417.  
  418. /*
  419.  * Copy from infilename to outfilename, PEM encoding as you go along,
  420.  * and with breaks every
  421.  * pem_lines lines.
  422.  * If clearfilename is non-NULL, first output that file preceded by a
  423.  * special header line.
  424.  */
  425. static
  426. int pem_file(char *infilename, char *outfilename, char *clearfilename)
  427. {
  428.     char buffer[MAX_LINE_SIZE];
  429.     int i, rc, bytesRead, lines = 0;
  430.     int noSections, currentSection = 1;
  431.     long fileLen;
  432.     crcword crc;
  433.     FILE *inFile, *outFile, *clearFile;
  434.     char *blocktype = "MESSAGE";
  435.  
  436.     /* open input file as binary */
  437.     if ((inFile = fopen(infilename,FOPRBIN)) == NULL)
  438.         return 1;
  439.  
  440.     if (!outfilename || pem_lines == 0) {
  441.         noSections = 1;
  442.     } else {
  443.         /* Evaluate how many parts this file will comprise */
  444.         fseek(inFile,0L,SEEK_END);
  445.         fileLen = ftell(inFile);
  446.         rewind(inFile);
  447.         noSections = (fileLen + BYTES_PER_SECTION - 1) / BYTES_PER_SECTION;
  448.         if (noSections > 99) {
  449.             pem_lines = ((fileLen+LINE_LEN-1)/LINE_LEN + 98) / 99;
  450.             noSections = (fileLen + BYTES_PER_SECTION - 1) / BYTES_PER_SECTION;
  451.             fprintf(pgpout, "value for \"armorlines\" is too low, using %d\n", pem_lines);
  452.         }
  453.     }
  454.     
  455.     if (outfilename == NULL) {
  456.         outFile = stdout;
  457.     } else {
  458.         if (noSections > 1) {
  459.             force_extension(outfilename, ASC_EXTENSION);
  460.             outFile = fopen (numFilename (outfilename, 1, noSections), FOPWTXT);
  461.         } else {
  462.             outFile = fopen(outfilename,FOPWTXT);
  463.         }
  464.     }
  465.  
  466.     if (outFile == NULL) {
  467.         fclose(inFile);
  468.         return 1;
  469.     }
  470.  
  471.     if (clearfilename) {
  472.         if ((clearFile = fopen(clearfilename,FOPRTXT)) == NULL) {
  473.             fclose (inFile);
  474.             if (outFile != stdout)
  475.                 fclose (outFile);
  476.             return 1;
  477.         }
  478.         fprintf (outFile, "-----BEGIN PGP SIGNED MESSAGE-----\n\n");
  479.         while ((i = getline(buffer, sizeof buffer, clearFile)) >= 0)
  480.         {
  481.             /* Quote lines beginning with '-' as per RFC1113;
  482.              * Also quote lines beginning with "From "; this is
  483.              * for Unix mailers which add ">" to such lines.
  484.              */
  485.             if (buffer[0] == '-' || strncmp(buffer, "From ", 5)==0)
  486.                 fputs("- ", outFile);
  487.             fputs(buffer, outFile);
  488.             /* If there is more on this line, copy it */
  489.             if (i == 0)
  490.                 if (copyline(clearFile, outFile) <= 0)
  491.                     break;
  492.             fputc('\n', outFile);
  493.         }
  494.         fclose (clearFile);
  495.         putc('\n', outFile);
  496.         blocktype = "SIGNATURE";
  497.     }
  498.  
  499.  
  500.     if (noSections == 1) {
  501.         byte ctb = 0;
  502.         ctb = getc(inFile);
  503.         if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE))
  504.             blocktype = "PUBLIC KEY BLOCK";
  505.         fprintf (outFile, "-----BEGIN PGP %s-----\n",blocktype);
  506.         rewind(inFile);
  507.     } else {
  508.         fprintf (outFile, "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n",
  509.                     1, noSections);
  510.     }
  511.     fprintf (outFile, "Version: %s\n",LANG (rel_version));
  512.     if (globalCommentString[0])
  513.         fprintf (outFile, "Comment: %s\n", globalCommentString);
  514.     fprintf (outFile, "\n");
  515.  
  516.     init_crc();
  517.     crc = CRCINIT;
  518.  
  519.     while((bytesRead = fread(buffer,1,LINE_LEN,inFile)) > 0) {
  520.         /* Munge up LINE_LEN characters */
  521.         if (bytesRead < LINE_LEN)
  522.             fill0 (buffer+bytesRead, LINE_LEN-bytesRead);
  523.  
  524.         crc = crcbytes((byte *)buffer, bytesRead, crc);
  525.         for (i=0; i<bytesRead-3; i+=3)
  526.             outdec(buffer+i, outFile, 3);
  527.         outdec(buffer+i, outFile, bytesRead-i);
  528.         putc('\n',outFile);
  529.  
  530.         if (++lines == pem_lines && currentSection < noSections) {
  531.             lines = 0;
  532.             outcrc (crc, outFile);
  533.             fprintf(outFile,"-----END PGP MESSAGE, PART %02d/%02d-----\n\n",
  534.                 currentSection, noSections);
  535.             if (write_error(outFile)) {
  536.                 fclose(outFile);
  537.                 return -1;
  538.             }
  539.             fclose (outFile);
  540.             outFile = fopen (numFilename (outfilename, ++currentSection, noSections), FOPWTXT);
  541.             if (outFile == NULL) {
  542.                 fclose(inFile);
  543.                 return -1;
  544.             }
  545.             fprintf(outFile,"-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n",
  546.                     currentSection, noSections);
  547.             fprintf(outFile,"\n");
  548.             crc = CRCINIT;
  549.         }
  550.     }
  551.     outcrc (crc, outFile);
  552.  
  553.     if (noSections == 1)
  554.         fprintf (outFile, "-----END PGP %s-----\n",blocktype);
  555.     else
  556.         fprintf(outFile,"-----END PGP MESSAGE, PART %02d/%02d-----\n",
  557.                 noSections, noSections);
  558.  
  559.     /* Done */
  560.     fclose(inFile);
  561.     rc = write_error(outFile);
  562.     if (outFile == stdout)
  563.         return rc;
  564.     fclose(outFile);
  565.  
  566.     if (rc)
  567.         return -1;
  568.  
  569.     if (clearfilename) {
  570.         fprintf (pgpout, LANG("\nClear signature file: %s\n"), outfilename);
  571.     } else if (noSections == 1) {
  572.         fprintf (pgpout, LANG("\nTransport armor file: %s\n"), outfilename);
  573.     } else {
  574.         fprintf (pgpout, LANG("\nTransport armor files: "));
  575.         for (i=1; i<=noSections; ++i)
  576.             fprintf (pgpout, "%s%s", numFilename(outfilename, i, noSections),
  577.                         i==noSections?"\n":", ");
  578.     }
  579.     return 0;
  580. }    /* pem_file */
  581.  
  582. /*     End PEM encode routines. */
  583.  
  584.  
  585. /*    PEM decode routines.
  586. */
  587.  
  588. static
  589. int dpem_buffer(char *inbuf, char *outbuf, int *outlength)
  590. {
  591.     unsigned char *bp;
  592.     int    length;
  593.     unsigned int c1,c2,c3,c4;
  594.     register int j;
  595.  
  596.     length = 0;
  597.     bp = (unsigned char *)inbuf;
  598.  
  599.     /* FOUR input characters go into each THREE output charcters */
  600.  
  601.     while (*bp != '\0') {
  602.         if (*bp&0x80 || (c1=asctobin[*bp])&0x80)
  603.             return -1;
  604.         ++bp;
  605.         if (*bp&0x80 || (c2=asctobin[*bp])&0x80)
  606.             return -1;
  607.         if (*++bp == PAD) {
  608.             c3 = c4 = 0;
  609.             length += 1;
  610.             if (c2 & 15)
  611.                 return -1;
  612.             if (strcmp((char *)bp, "==") == 0)
  613.                 bp += 1;
  614.             else if (strcmp((char *)bp, "=3D=3D") == 0)
  615.                 bp += 5;
  616.             else
  617.                 return -1;
  618.         } else if (*bp&0x80 || (c3=asctobin[*bp])&0x80) {
  619.                 return -1;
  620.         } else {
  621.             if (*++bp == PAD) {
  622.                 c4 = 0;
  623.                 length += 2;
  624.                 if (c3 & 3)
  625.                     return -1;
  626.                 if (strcmp((char *)bp, "=") == 0)
  627.                     ; /* All is well */
  628.                 else if (strcmp((char *)bp, "=3D") == 0)
  629.                     bp += 2;
  630.                 else
  631.                     return -1;
  632.             } else if (*bp&0x80 || (c4=asctobin[*bp])&0x80) {
  633.                 return -1;
  634.             } else {
  635.                 length += 3;
  636.             }
  637.         }
  638.         ++bp;
  639.         j = (c1 << 2) | (c2 >> 4);
  640.         *outbuf++=j;
  641.         j = (c2 << 4) | (c3 >> 2);
  642.         *outbuf++=j;
  643.         j = (c3 << 6) | c4;
  644.         *outbuf++=j;
  645.     }
  646.  
  647.     *outlength = length;
  648.     return 0;    /* normal return */
  649.  
  650. }    /* dpem_buffer */
  651.  
  652. static char pemfilename[MAX_PATH];
  653. /*
  654.  * try to open the next file of a multi-part armored file
  655.  * the sequence number is expected at the end of the file name
  656.  */
  657. static FILE *
  658. open_next(void)
  659. {
  660.     char *p, *s, c;
  661.     FILE *fp;
  662.  
  663.     p = pemfilename + strlen(pemfilename);
  664.     while (--p >= pemfilename && isdigit(*p)) {
  665.         if (*p != '9') {
  666.             ++*p;
  667.             return fopen(pemfilename, FOPRPEM);
  668.         }
  669.         *p = '0';
  670.     }
  671.  
  672.     /* need an extra digit */
  673.     if (p >= pemfilename) {
  674.         /* try replacing character ( .as0 -> .a10 ) */
  675.         c = *p;
  676.         *p = '1';
  677.         if ((fp = fopen(pemfilename, FOPRPEM)) != NULL)
  678.             return fp;
  679.         *p = c;    /* restore original character */
  680.     }
  681.     ++p;
  682.     for (s = p + strlen(p); s >= p; --s)
  683.         s[1] = *s;
  684.     *p = '1'; /* insert digit ( fn0 -> fn10 ) */
  685.  
  686.     return fopen(pemfilename, FOPRPEM);
  687. }
  688.  
  689. /*
  690.  * Copy from in to out, decoding as you go, with handling for multiple
  691.  * 500-line blocks of encoded data.
  692.  */
  693. static
  694. int pemdecode(FILE *in, FILE *out)
  695. {
  696.     char inbuf[80];
  697.     char outbuf[80];
  698.  
  699.     int i, n, status;
  700.     int line;
  701.     int section, currentSection = 1;
  702.     int noSections = 0;
  703.     int gotcrc = 0;
  704.     long crc=CRCINIT, chkcrc = -1;
  705.     char crcbuf[4];
  706.     int ret_code = 0;
  707.     int end_of_message;
  708.  
  709.     init_crc();
  710.  
  711.     for (line = 1; ; line++) {    /* for each input line */
  712.         if (get_armor_line(inbuf, in) == NULL) {
  713.             end_of_message = 1;
  714.         } else {
  715.             end_of_message = (strncmp(inbuf,"-----END PGP MESSAGE,", 21) == 0);
  716.             ++infile_line;
  717.         }
  718.  
  719.         if (currentSection!=noSections && end_of_message) {
  720.             /* End of this section */
  721.             if (gotcrc) {
  722.                 if (chkcrc != crc) {
  723.                     fprintf(pgpout,LANG("ERROR: Bad ASCII armor checksum in section %d.\n"), currentSection);
  724.                     ret_code = -1;    /* continue with decoding to see if there are other bad parts */
  725.                 }
  726.             }
  727.             gotcrc = 0;
  728.             crc = CRCINIT;
  729.             section = 0;
  730.  
  731.             /* Try and find start of next section */
  732.             do {
  733.                 if (get_armor_line(inbuf,in) == NULL) {
  734.                     FILE *nextf;
  735.                     if ((nextf = open_next()) != NULL) {
  736.                         fclose(in);
  737.                         in = nextf;
  738.                         continue;
  739.                     }
  740.                     fprintf(pgpout,LANG("Can't find section %d.\n"),currentSection + 1);
  741.                     return -1;
  742.                 }
  743.                 ++infile_line;
  744.             }
  745.             while (strncmp(inbuf,"-----BEGIN PGP MESSAGE",22));
  746.  
  747.             /* Make sure this section is the correct one */
  748.             if (2 != sscanf(inbuf,"-----BEGIN PGP MESSAGE, PART %d/%d",
  749.                 §ion,&noSections))
  750.             {
  751.                 fprintf(pgpout,LANG("Badly formed section header, part %d.\n"),
  752.                     currentSection+1);
  753.                 return -1;
  754.             }
  755.             if (section != ++currentSection) {
  756.                 fprintf(pgpout,LANG("Sections out of order, expected part %d"),currentSection);
  757.                 if (section)
  758.                     fprintf(pgpout,LANG(", got part %d\n"),section);
  759.                 else
  760.                     fputc('\n',pgpout);
  761.                 return -1;
  762.             }
  763.  
  764.             /* Skip header after BEGIN line */
  765.             do {
  766.                 ++infile_line;
  767.                 if (get_armor_line(inbuf, in) == NULL) {
  768.                     fprintf(pgpout,LANG("ERROR: Hit EOF in header of section %d.\n"),
  769.                         currentSection);
  770.                     return -1;
  771.                 }
  772.             } while (inbuf[0] != '\0');
  773.  
  774.             /* Continue decoding */
  775.             continue;
  776.         }
  777.  
  778.         /* Quit when hit the -----END PGP MESSAGE----- line or a blank,
  779.             or handle checksum */
  780.         if (inbuf[0] == PAD) {    /* Checksum lines start with PAD char */
  781.             /* If the already-armored file is sent through MIME
  782.              * and gets armored again, '=' will become '=3D'.
  783.              * To make life easier, we detect and work around this
  784.              * idiosyncracy.
  785.              */
  786.             if (strlen(inbuf) == 7 &&
  787.                 inbuf[1] == '3' && inbuf[2] == 'D')
  788.                 status = dpem_buffer(inbuf+3, crcbuf, &n);
  789.             else
  790.                 status = dpem_buffer(inbuf+1, crcbuf, &n);
  791.             if ( status < 0 || n != 3 ) {
  792.                 fprintf(pgpout,LANG("ERROR: Badly formed ASCII armor checksum, line %d.\n"),line);
  793.                 return -1;
  794.             }
  795.             chkcrc = (((long)crcbuf[0]<<16)&0xff0000L) +
  796.                 ((crcbuf[1]<<8)&0xff00L) + (crcbuf[2]&0xffL);
  797.             gotcrc = 1;
  798.             continue;
  799.         }
  800.         if (inbuf[0] == '\0') {
  801.             fprintf(pgpout,LANG("WARNING: No ASCII armor `END' line.\n"));
  802.             break;
  803.         }
  804.         if (strncmp(inbuf, "-----END PGP ", 13) == 0)
  805.             break;
  806.  
  807.         status = dpem_buffer(inbuf,outbuf,&n);
  808.  
  809.         if (status == -1) {
  810.             fprintf(pgpout,LANG("ERROR: Bad ASCII armor character, line %d.\n"), line);
  811.             gotcrc = 1;    /* this will print part number, continue with next part */
  812.             ret_code = -1;
  813.         }
  814.  
  815.         if (n > sizeof outbuf) {
  816.             fprintf(pgpout,LANG("ERROR: Bad ASCII armor line length %d on line %d.\n"),
  817.                     n, line);
  818.             return -1;
  819.         }
  820.  
  821.         crc = crcbytes((byte *)outbuf, n, crc);
  822.         if (fwrite(outbuf,1,n,out) != n) {
  823.             ret_code = -1;
  824.             break;
  825.         }
  826.  
  827.     }    /* line */
  828.  
  829.     if (gotcrc) {
  830.         if (chkcrc != crc) {
  831.             fprintf(pgpout,LANG("ERROR: Bad ASCII armor checksum"));
  832.             if (noSections > 0)
  833.                 fprintf(pgpout,LANG(" in section %d"), noSections);
  834.             fputc('\n',pgpout);
  835.             return -1;
  836.         }
  837.     } else {
  838.         fprintf(pgpout,LANG("Warning: Transport armor lacks a checksum.\n"));
  839.     }
  840.  
  841.     return ret_code;    /* normal return */
  842. }   /* pemdecode */
  843.  
  844.  
  845. static
  846. boolean is_pemfile(char *infile)
  847. {
  848.     FILE    *in;
  849.     char    inbuf[80];
  850.     char    outbuf[80];
  851.     int     n, status;
  852.     long    il;
  853.  
  854.     if ((in = fopen(infile, FOPRPEM)) == NULL) {
  855.         /* can't open file */
  856.         return FALSE;
  857.     }
  858.  
  859.     /* Read to infile_line before we begin looking */
  860.     for (il=0; il<infile_line; ++il) {
  861.         if (get_armor_line(inbuf, in) == NULL) {
  862.             fclose(in);
  863.             return FALSE;
  864.         }
  865.     }
  866.  
  867.     /* search file for header line */
  868.     for (;;) {
  869.         if (get_armor_line(inbuf, in) == NULL) {
  870.             break;
  871.         } else {
  872.             if (strncmp(inbuf, "-----BEGIN PGP ", 15) == 0) {
  873.                 if (strncmp(inbuf,"-----BEGIN PGP SIGNED MESSAGE-----",34)==0) {
  874.                     fclose(in);
  875.                     return TRUE;
  876.                 }
  877.                 do {
  878.                     if (get_armor_line(inbuf, in) == NULL)
  879.                         break;
  880. #ifndef STRICT_PEM
  881.                     if (dpem_buffer(inbuf,outbuf,&n) == 0 && n == 48)
  882.                     {
  883.                         fclose(in);
  884.                         return TRUE;
  885.                     }
  886. #endif
  887.                 } while (inbuf[0] != '\0');
  888.                 if (get_armor_line(inbuf, in) == NULL)
  889.                     break;
  890.                 status = dpem_buffer(inbuf,outbuf,&n);
  891.                 if (status < 0)
  892.                     break;
  893.                 fclose(in);
  894.                 return TRUE;
  895.             }
  896.         }
  897.     }
  898.  
  899.     fclose(in);
  900.     return FALSE;
  901.  
  902. }    /* is_pemfile */
  903.  
  904.  
  905. static
  906. int dpem_file(char *infile, char *outfile)
  907. {
  908.     FILE    *in, *out;
  909.     char    buf[MAX_LINE_SIZE];
  910.     char    outbuf[80];
  911.     int    status, n;
  912.     long    il, fpos;
  913.     char    *litfile = NULL;
  914.  
  915.     if ((in = fopen(infile, FOPRPEM)) == NULL) {
  916.         fprintf(pgpout,LANG("ERROR: Can't find file %s\n"), infile);
  917.         return 10;
  918.     }
  919.     strcpy(pemfilename, infile);    /* store filename for multi-parts */
  920.  
  921.     /* Skip to infile_line */
  922.     for (il=0; il<infile_line; ++il) {
  923.         if (get_armor_line(buf, in) == NULL) {
  924.             fclose(in);
  925.             return -1;
  926.         }
  927.     }
  928.  
  929.     /* Loop through file, searching for header.  Decode anything with a
  930.        header, complain if there were no headers. */
  931.  
  932.     /* search file for header line */
  933.     for (;;) {
  934.         ++infile_line;
  935.         if (get_armor_line(buf, in) == NULL) {
  936.             fprintf(pgpout,LANG("ERROR: No ASCII armor `BEGIN' line!\n"));
  937.             fclose(in);
  938.             return 12;
  939.         }
  940.         if (strncmp(buf, "-----BEGIN PGP ", 15) == 0)
  941.             break;
  942.     }
  943.     if (strncmp(buf, "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0) {
  944.         FILE    *litout;
  945.         char    *canonfile, *p;
  946.         int    nline;
  947.  
  948.         litfile = tempfile(TMP_WIPE|TMP_TMPDIR);
  949.         if ((litout = fopen (litfile, FOPWTXT)) == NULL) {
  950.             fprintf(pgpout,LANG("\n\007Unable to write ciphertext output file '%s'.\n"), litfile);
  951.             fclose(in);
  952.             return -1;
  953.         }
  954.         /* Skip header lines until a blank is hit */
  955.         do {
  956.             ++infile_line;
  957.             status = skipline(in);
  958.         } while (status != 0);
  959.         /* Ignore error; getline will discover it again */
  960.         status = 0;
  961.         for (;;) {
  962.             ++infile_line;
  963.             nline = status;
  964.             status = getline(buf, sizeof buf, in);
  965.             if (status < 0) {
  966.                 fprintf(pgpout,LANG("ERROR: ASCII armor decode input ended unexpectedly!\n"));
  967.                 fclose(in);
  968.                 fclose(litout);
  969.                 rmtemp (litfile);
  970.                 return 12;
  971.             }
  972.  
  973.             if (strncmp(buf,"-----BEGIN PGP ", 15) == 0)
  974.                 break;
  975.             if (nline)
  976.                 putc('\n', litout);
  977.             /* De-quote lines starting with '- ' */
  978.             fputs(buf + ((buf[0]=='-'&&buf[1]==' ')?2:0), litout);
  979.             /* Copy trailing part of line, if any. */
  980.             if (!status)
  981.                 status = copyline(in, litout);
  982.             /* Ignore error; getline will discover it again */
  983.         }
  984.         fflush (litout);
  985.         if (ferror(litout)) {
  986.             fclose(litout);
  987.             fclose(in);
  988.             rmtemp (litfile);
  989.             return -1;
  990.         }
  991.         fclose (litout);
  992.         canonfile = tempfile(TMP_WIPE|TMP_TMPDIR);
  993.         strip_spaces = TRUE;
  994.         make_canonical (litfile, canonfile);
  995.         rmtemp (litfile);
  996.         litfile = canonfile;
  997.     }
  998.  
  999.     /* Skip header after BEGIN line */
  1000.     do {
  1001.         ++infile_line;
  1002.         fpos = ftell(in);
  1003.         if (get_armor_line(buf, in) == NULL) {
  1004.             fprintf(pgpout,LANG("ERROR: Hit EOF in header.\n"));
  1005.             fclose(in);
  1006.             return 13;
  1007.         }
  1008. #ifndef STRICT_PEM
  1009.         if (dpem_buffer(buf,outbuf,&n) == 0 && n == 48) {
  1010.             fseek(in, fpos, SEEK_SET);
  1011.             --infile_line;
  1012.             break;
  1013.         }
  1014. #endif
  1015.     } while (buf[0] != '\0');
  1016.  
  1017.     if ((out = fopen(outfile, FOPWBIN)) == NULL) {
  1018.         fprintf(pgpout,LANG("\n\007Unable to write ciphertext output file '%s'.\n"), outfile);
  1019.         fclose(in);
  1020.         return -1;
  1021.     }
  1022.  
  1023.     status = pemdecode(in, out);
  1024.  
  1025.     if (litfile) {
  1026.         /* Glue the literal file read above to the signature */
  1027.         char lit_mode=MODE_TEXT;    
  1028.         word32 dummystamp = 0;
  1029.         FILE *f = fopen(litfile,FOPRBIN);
  1030.         write_ctb_len (out, CTB_LITERAL2_TYPE, fsize(f)+6, FALSE);
  1031.         fwrite ( &lit_mode, 1, 1, out );    /*    write lit_mode */
  1032.         fputc ('\0', out);            /* No filename */
  1033.         fwrite ( &dummystamp, 1, sizeof(dummystamp), out); /* dummy timestamp */
  1034.         copyfile(f,out,-1L);        /* Append literal file */
  1035.         fclose (f);
  1036.         rmtemp(litfile);
  1037.     }
  1038.  
  1039.     if (write_error(out))
  1040.         status = -1;
  1041.     fclose(out);
  1042.     fclose(in);
  1043.     return status;
  1044. }   /* dpem_file */
  1045.  
  1046. /* Entry points for generic interface names */
  1047. int
  1048. armor_file (char *infile, char *outfile, char *filename, char *clearname)
  1049. {
  1050.     if (verbose)
  1051.         fprintf(pgpout,"armor_file: infile = %s, outfile = %s, filename = %s, clearname = %s\n",
  1052.             infile, outfile, filename, clearname);
  1053.     return pem_file (infile, outfile, clearname);
  1054. }
  1055.  
  1056. int
  1057. de_armor_file(char *infile, char *outfile, long *curline)
  1058. {
  1059.     int status;
  1060.  
  1061.     if (verbose)
  1062.         fprintf(pgpout,"de_armor_file: infile = %s, outfile = %s, curline = %ld\n",
  1063.             infile, outfile, *curline);
  1064.     infile_line = (curline ? *curline : 0);
  1065.     status = dpem_file (infile, outfile);
  1066.     if (curline)
  1067.         *curline = infile_line;
  1068.     return status;
  1069. }
  1070.  
  1071. boolean
  1072. is_armor_file (char *infile, long startline)
  1073. {
  1074.     infile_line = startline;
  1075.     return is_pemfile (infile);
  1076. }
  1077.